package ly.gupao.edu.thread;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author: liyang
 * @date：2018/5/16 0016
 * describe：线程池构造工厂
 */
public class ExecutorServiceFactory {

    private static ExecutorServiceFactory executorServiceFactory = new ExecutorServiceFactory();

    private ExecutorServiceFactory(){}

    private static ExecutorService executor;

    /**
     * 获取ExecutorServiceFactory实例
     * @return
     */
    public ExecutorServiceFactory getInstance(){
        return executorServiceFactory;
    }


    /**
     * 创建一个线程池，它可安排在给定延迟后运行命令或者定期地执行。
     * @return
     */
    public static ExecutorService createScheduledThreadPool(){
        executor = new ScheduledThreadPoolExecutor(1, getThreadFactory());
        return executor;
    }

    /**
     * 创建一个可根据需要创建新线程的线程池，但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言，这些线程池通常可提高程序性能。调用
     * execute 将重用以前构造的线程（如果线程可用）。如果现有线程没有可用的，则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60
     * 秒钟未被使用的线程。因此，长时间保持空闲的线程池不会使用任何资源。注意，可以使用 ThreadPoolExecutor
     * 构造方法创建具有类似属性但细节不同（例如超时参数）的线程池。
     *
     * @return
     */
    public static ExecutorService createCacheThreadPool(){
        executor =  new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                60L, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>(),
                getThreadFactory());
        return executor;
    }

    /**
     * 创建一个可重用固定线程数的线程池，以共享的无界队列方式来运行这些线程。在任意点，在大多数 nThreads
     * 线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务
     * ，则在有可用线程之前，附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止
     * ，那么一个新线程将代替它执行后续的任务（如果需要）。在某个线程被显式地关闭之前，池中的线程将一直存在。
     *
     * @return
     */
    public static ExecutorService createFixedThreadPool(int count){
        executor = new ThreadPoolExecutor(count, count,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>(),
                getThreadFactory());
        return executor;
    }

    /**
     * 获取一个ThreadFactory
     * @return
     */
    private static ThreadFactory getThreadFactory(){
        return new ThreadFactory() {
            AtomicInteger integer = new AtomicInteger();
            @Override
            public Thread newThread(Runnable r) {
                SecurityManager manager = new SecurityManager();
                ThreadGroup group = manager.getThreadGroup() != null ? manager.getThreadGroup() : Thread.currentThread().getThreadGroup();
                Thread thread = new Thread(group, r);
                thread.setName("thread ---" + integer.incrementAndGet());
                return thread;
            }
        };
    }


}
